package com.ringtheweb.common.util;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Utility class for all kind operations on {@link String}.
 *
 * @author ldewavri
 *
 */
public class StringUtils {

    /** Environment property pattern */
    private final static Pattern ENV_PROPERTY_PATTERN = Pattern.compile("(\\$\\{[^\\$\\{\\}]+\\})");

    /** New line REGEX. */
    public static String CR_REGEX = "[\\n\\r]|(?:\\r\\n)";

    public static boolean hasText(String str) {
        if (!hasLength(str)) {
            return false;
        }
        int strLen = str.length();
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return true;
            }
        }
        return false;
    }

    public static boolean hasLength(String str) {
        return (str != null && str.length() > 0);
    }

    public static String unqualify(String name) {
        return unqualify(name, '.');
    }

    public static String unqualify(String name, char sep) {
        return name.substring(name.lastIndexOf(sep) + 1, name.length());
    }

    public static boolean isEmpty(String string) {
        return string == null || string.trim().length() == 0;
    }

    public static String nullIfEmpty(String string) {
        return isEmpty(string) ? null : string;
    }

    public static String toString(Object bean) {
        try {
            PropertyDescriptor[] props = Introspector.getBeanInfo(
                    bean.getClass()).getPropertyDescriptors();
            StringBuilder builder = new StringBuilder();
            for (PropertyDescriptor descriptor : props) {
                builder.append(descriptor.getName()).append("=").append(
                        descriptor.getReadMethod().invoke(bean)).append("; ");
            }
            return builder.toString();
        } catch (Exception e) {
            return "";
        }
    }



    /**
     * Fill a string with a char from the right
     * @param toInsert the String to fill
     * @param finalLength the final length of the string
     * @param defaultChar the default char
     * @return the formatted String.
     */

    public static String rightPad(String string,int finalLength,char defaultChar) {

        StringBuilder stringBuilder = new StringBuilder(string);
        while (stringBuilder.length() < finalLength) {
            stringBuilder.insert(stringBuilder.length(), defaultChar);
        }

        return stringBuilder.toString().substring(0,finalLength);

    }

    /**
     * Fill a string with a char from the left
     * @param toInsert the String to fill
     * @param finalLength the final length of the string
     * @param defaultChar the default char
     * @return the formatted String.
     */
    public static String leftPad(String string,int finalLength,char defaultChar) {

        StringBuilder stringBuilder = new StringBuilder(string);
        while (stringBuilder.length() < finalLength) {
            stringBuilder.insert(0, defaultChar);
        }

        return stringBuilder.toString().substring(0,finalLength);

    }

    public static String[] split(String strings, String delims) {
        if (strings == null) {
            return new String[0];
        } else {
            StringTokenizer tokens = new StringTokenizer(strings, delims);
            String[] result = new String[tokens.countTokens()];
            int i = 0;
            while (tokens.hasMoreTokens()) {
                result[i++] = tokens.nextToken();
            }
            return result;
        }
    }

    /**
     * Transform every occurence of ${} i the given String by the value of a matched environment property.
     * @param propertyExpression the string to be evaluated
     * @return the formatted string
     */
    public static String replaceEnvironmentVariables(String chaine) {

        Assert.notNull(chaine, "the passed String can not be null or empty");

        Map<String,String> envVariables = System.getenv();

        int lastFoundIndex = 0;
        StringBuffer rSb = new StringBuffer();
        Matcher matcher = ENV_PROPERTY_PATTERN.matcher(chaine);
        while ( matcher.find( )) {
            int start = matcher.start(0);
            int end = matcher.end(0);

            // Suppression ent�te '${' et fin '}'
            String propertyName = matcher.group(0).substring(2, matcher.group(0).length()-1);
            String newValue = matcher.group(0);
            if (envVariables.containsKey(propertyName)) {
                newValue = envVariables.get(propertyName);
            }
            String notPattern = chaine.substring(lastFoundIndex, start);
            rSb.append(notPattern);
            rSb.append(newValue);
            lastFoundIndex = end;
        }
        rSb.append(chaine.substring(lastFoundIndex, chaine.length()));

        return rSb.toString();
    }


    /**
     * Delete the EOL characters (Unix and Windows)
     * @param string the string with EOL chars
     * @return the formatted String
     */
    public static String deleteEOLChars(String string) {
        return string.replaceAll(CR_REGEX, "");
    }

    /**
     * Get the first chars of a String (avoid {@link IndexOutOfBoundsException of String} of .
     * If given length is larger than the string length, the original string is returned.
     *
     * @param string the string
     * @param nbrOfChars the number of characters in the returned String
     * @return the substring of the original String
     */
    public static String getFirstChars(String string,int nbrOfChars) {
        if (nbrOfChars == 0) return "";

        if (string.length() <= nbrOfChars) {
            return string;
        }
        return string.substring(0,nbrOfChars);

    }


    public static String toString(Object... objects) {
        return toString(" ", objects);
    }

    public static String toString(String sep, Object... objects) {
        if (objects.length == 0)
            return "";
        StringBuilder builder = new StringBuilder();
        for (Object object : objects) {
            builder.append(sep).append(object);
        }
        return builder.substring(2);
    }

    public static String toClassNameString(String sep, Object... objects) {
        if (objects.length == 0)
            return "";
        StringBuilder builder = new StringBuilder();
        for (Object object : objects) {
            builder.append(sep);
            if (object == null) {
                builder.append("null");
            } else {
                builder.append(object.getClass().getName());
            }
        }
        return builder.substring(2);
    }

    public static String toString(String sep, Class<?>... classes) {
        if (classes.length == 0)
            return "";
        StringBuilder builder = new StringBuilder();
        for (Class<?> clazz : classes) {
            builder.append(sep).append(clazz.getName());
        }
        return builder.substring(2);
    }

    public static String toString(InputStream in) throws IOException {
        StringBuffer out = new StringBuffer();
        byte[] b = new byte[4096];
        for (int n; (n = in.read(b)) != -1;) {
            out.append(new String(b, 0, n));
        }
        return out.toString();
    }

    public static String nullToEmpty (String s) {
    	return hasText(s) ? s : "" ;
    }
    
    /**
     * Get digits of a String
     *
     * @param string the String to process
     * @return the extracted digits as a String
     */
    public static String getDigitsOnly(String string) {
        StringBuffer digitsOnly = new StringBuffer ();
        char c;
        for (int i = 0; i < string.length (); i++) {
          c = string.charAt (i);
          if (Character.isDigit (c)) {
            digitsOnly.append (c);
          }
        }
        return digitsOnly.toString ();
      }

}
